/***************************************************************************
 *            rtfactn.c
 *
 *  Sun Aug 13 13:03:57 2006
 *  Copyright  2006  Alexander P Telenga
 *  telenga@gmail.com
 ****************************************************************************/

/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <ctype.h>
#include "include/rtf_parser.h"


/* RTF parser tables */

/* Property descriptions */
PROP rgprop [ipropMax] = {
    actnByte,   propChp,    offsetof(CHP, fBold),       /* ipropBold */
    actnByte,   propChp,    offsetof(CHP, fItalic),     /* ipropItalic */
    actnByte,   propChp,    offsetof(CHP, fUnderline),  /* ipropUnderline */
    actnWord,   propPap,    offsetof(PAP, xaLeft),      /* ipropLeftInd */
    actnWord,   propPap,    offsetof(PAP, xaRight),     /* ipropRightInd */
    actnWord,   propPap,    offsetof(PAP, xaFirst),     /* ipropFirstInd */
    actnWord,   propSep,    offsetof(SEP, cCols),       /* ipropCols */
    actnWord,   propSep,    offsetof(SEP, xaPgn),       /* ipropPgnX */
    actnWord,   propSep,    offsetof(SEP, yaPgn),       /* ipropPgnY */
    actnWord,   propDop,    offsetof(DOP, xaPage),      /* ipropXaPage */
    actnWord,   propDop,    offsetof(DOP, yaPage),      /* ipropYaPage */
    actnWord,   propDop,    offsetof(DOP, xaLeft),      /* ipropXaLeft */
    actnWord,   propDop,    offsetof(DOP, xaRight),     /* ipropXaRight */
    actnWord,   propDop,    offsetof(DOP, yaTop),       /* ipropYaTop */
    actnWord,   propDop,    offsetof(DOP, yaBottom),    /* ipropYaBottom */
    actnWord,   propDop,    offsetof(DOP, pgnStart),    /* ipropPgnStart */
    actnByte,   propSep,    offsetof(SEP, sbk),         /* ipropSbk */
    actnByte,   propSep,    offsetof(SEP, pgnFormat),   /* ipropPgnFormat */
    actnByte,   propDop,    offsetof(DOP, fFacingp),    /* ipropFacingp */
    actnByte,   propDop,    offsetof(DOP, fLandscape),  /* ipropLandscape */
    actnByte,   propPap,    offsetof(PAP, just),        /* ipropJust */
    actnSpec,   propPap,    0,                          /* ipropPard */
    actnSpec,   propChp,    0,                          /* ipropPlain */
    actnSpec,   propSep,    0,                          /* ipropSectd */
};

/* Keyword descriptions */
SYM rgsymRtf[] = {
/*  keyword     dflt    fPassDflt   kwd         idx */
    "b",        1,      fFalse,     kwdProp,    ipropBold,
    "u",        1,      fFalse,     kwdProp,    ipropUnderline,
    "i",        1,      fFalse,     kwdProp,    ipropItalic,
    "li",       0,      fFalse,     kwdProp,    ipropLeftInd,
    "ri",       0,      fFalse,     kwdProp,    ipropRightInd,
    "fi",       0,      fFalse,     kwdProp,    ipropFirstInd,
    "cols",     1,      fFalse,     kwdProp,    ipropCols,
    "sbknone",  sbkNon, fTrue,      kwdProp,    ipropSbk,
    "sbkcol",   sbkCol, fTrue,      kwdProp,    ipropSbk,
    "sbkeven",  sbkEvn, fTrue,      kwdProp,    ipropSbk,
    "sbkodd",   sbkOdd, fTrue,      kwdProp,    ipropSbk,
    "sbkpage",  sbkPg,  fTrue,      kwdProp,    ipropSbk,
    "pgnx",     0,      fFalse,     kwdProp,    ipropPgnX,
    "pgny",     0,      fFalse,     kwdProp,    ipropPgnY,
    "pgndec",   pgDec,  fTrue,      kwdProp,    ipropPgnFormat,
    "pgnucrm",  pgURom, fTrue,      kwdProp,    ipropPgnFormat,
    "pgnlcrm",  pgLRom, fTrue,      kwdProp,    ipropPgnFormat,
    "pgnucltr", pgULtr, fTrue,      kwdProp,    ipropPgnFormat,
    "pgnlcltr", pgLLtr, fTrue,      kwdProp,    ipropPgnFormat,
    "qc",       justC,  fTrue,      kwdProp,    ipropJust,
    "ql",       justL,  fTrue,      kwdProp,    ipropJust,
    "qr",       justR,  fTrue,      kwdProp,    ipropJust,
    "qj",       justF,  fTrue,      kwdProp,    ipropJust,
    "paperw",   12240,  fFalse,     kwdProp,    ipropXaPage,
    "paperh",   15480,  fFalse,     kwdProp,    ipropYaPage,
    "margl",    1800,   fFalse,     kwdProp,    ipropXaLeft,
    "margr",    1800,   fFalse,     kwdProp,    ipropXaRight,
    "margt",    1440,   fFalse,     kwdProp,    ipropYaTop,
    "margb",    1440,   fFalse,     kwdProp,    ipropYaBottom,
    "pgnstart", 1,      fTrue,      kwdProp,    ipropPgnStart,
    "facingp",  1,      fTrue,      kwdProp,    ipropFacingp,
    "landscape",1,      fTrue,      kwdProp,    ipropLandscape,
    "par",      0,      fFalse,     kwdChar,    0x0a,
    "\0x0a",    0,      fFalse,     kwdChar,    0x0a,
    "\0x0d",    0,      fFalse,     kwdChar,    0x0a,
    "tab",      0,      fFalse,     kwdChar,    0x09,
    "ldblquote",0,      fFalse,     kwdChar,    '"',
    "rdblquote",0,      fFalse,     kwdChar,    '"',
    "bin",      0,      fFalse,     kwdSpec,    ipfnBin,
    "*",        0,      fFalse,     kwdSpec,    ipfnSkipDest,
    "'",        0,      fFalse,     kwdSpec,    ipfnHex,
    "author",   0,      fFalse,     kwdDest,    idestSkip,
    "buptim",   0,      fFalse,     kwdDest,    idestSkip,
    "colortbl", 0,      fFalse,     kwdDest,    idestSkip,
    "comment",  0,      fFalse,     kwdDest,    idestSkip,
    "creatim",  0,      fFalse,     kwdDest,    idestSkip,
    "doccomm",  0,      fFalse,     kwdDest,    idestSkip,
    "fonttbl",  0,      fFalse,     kwdDest,    idestSkip,
    "footer",   0,      fFalse,     kwdDest,    idestSkip,
    "footerf",  0,      fFalse,     kwdDest,    idestSkip,
    "footerl",  0,      fFalse,     kwdDest,    idestSkip,
    "footerr",  0,      fFalse,     kwdDest,    idestSkip,
    "footnote", 0,      fFalse,     kwdDest,    idestSkip,
    "ftncn",    0,      fFalse,     kwdDest,    idestSkip,
    "ftnsep",   0,      fFalse,     kwdDest,    idestSkip,
    "ftnsepc",  0,      fFalse,     kwdDest,    idestSkip,
    "header",   0,      fFalse,     kwdDest,    idestSkip,
    "headerf",  0,      fFalse,     kwdDest,    idestSkip,
    "headerl",  0,      fFalse,     kwdDest,    idestSkip,
    "headerr",  0,      fFalse,     kwdDest,    idestSkip,
    "info",     0,      fFalse,     kwdDest,    idestSkip,
    "keywords", 0,      fFalse,     kwdDest,    idestSkip,
    "operator", 0,      fFalse,     kwdDest,    idestSkip,
    "pict",     0,      fFalse,     kwdDest,    idestSkip,
    "printim",  0,      fFalse,     kwdDest,    idestSkip,
    "private1", 0,      fFalse,     kwdDest,    idestSkip,
    "revtim",   0,      fFalse,     kwdDest,    idestSkip,
    "rxe",      0,      fFalse,     kwdDest,    idestSkip,
    "stylesheet",   0,      fFalse,     kwdDest,    idestSkip,
    "subject",  0,      fFalse,     kwdDest,    idestSkip,
    "tc",       0,      fFalse,     kwdDest,    idestSkip,
    "title",    0,      fFalse,     kwdDest,    idestSkip,
    "txe",      0,      fFalse,     kwdDest,    idestSkip,
    "xe",       0,      fFalse,     kwdDest,    idestSkip,
    "{",        0,      fFalse,     kwdChar,    '{',
    "}",        0,      fFalse,     kwdChar,    '}',
    "\\",       0,      fFalse,     kwdChar,    '\\'
    };
int isymMax = sizeof(rgsymRtf) / sizeof(SYM);

/* */
/* %%Function: ecApplyPropChange */
/* */
/* Set the property identified by _iprop_ to the value _val_. */
/* */
/* */

int
ecApplyPropChange(IPROP iprop, int val)
{
    char *pb;

    if (rds == rdsSkip)                 /* If we're skipping text, */
        return ecOK;                    /* don't do anything. */

    switch (rgprop[iprop].prop)
    {
    case propDop:
        pb = (char *)&dop;
        break;
    case propSep:
        pb = (char *)&sep;
        break;
    case propPap:
        pb = (char *)&pap;
        break;
    case propChp:
        pb = (char *)&chp;
        break;
    default:
        if (rgprop[iprop].actn != actnSpec)
            return ecBadTable;
        break;
    }
    switch (rgprop[iprop].actn)
    {
    case actnByte:
        pb[rgprop[iprop].offset] = (unsigned char) val;
        break;
    case actnWord:
        (*(int *) (pb+rgprop[iprop].offset)) = val;
        break;
    case actnSpec:
        return ecParseSpecialProperty(iprop, val);
        break;
    default:
        return ecBadTable;
    }
    return ecOK;
}

/* */
/* %%Function: ecParseSpecialProperty */
/* */
/* Set a property that requires code to evaluate. */
/* */

int
ecParseSpecialProperty(IPROP iprop, int val)
{
    switch (iprop)
    {
    case ipropPard:
        memset(&pap, 0, sizeof(pap));
        return ecOK;
    case ipropPlain:
        memset(&chp, 0, sizeof(chp));
        return ecOK;
    case ipropSectd:
        memset(&sep, 0, sizeof(sep));
        return ecOK;
    default:
        return ecBadTable;
    }
    return ecBadTable;
}

/* */
/* %%Function: ecTranslateKeyword. */
/* */
/* Step 3. */
/* Search rgsymRtf for szKeyword and evaluate it appropriately. */
/* */
/* Inputs: */
/* szKeyword:   The RTF control to evaluate. */
/* param:       The parameter of the RTF control. */
/* fParam:      fTrue if the control had a parameter; (that is, if param is valid) */
/*              fFalse if it did not. */
/* */

int
ecTranslateKeyword(char *szKeyword, int param, bool fParam)
{
    int isym;

    /* search for szKeyword in rgsymRtf */

    for (isym = 0; isym < isymMax; isym++)
        if (strcmp(szKeyword, rgsymRtf[isym].szKeyword) == 0)
            break;
    if (isym == isymMax)            /* control word not found */
    {
        if (fSkipDestIfUnk)         /* if this is a new destination */
            rds = rdsSkip;          /* skip the destination */
                                    /* else just discard it */
        fSkipDestIfUnk = fFalse;
        return ecOK;
    }

    /* found it!  use kwd and idx to determine what to do with it. */

    fSkipDestIfUnk = fFalse;
    switch (rgsymRtf[isym].kwd)
    {
    case kwdProp:
        if (rgsymRtf[isym].fPassDflt || !fParam)
            param = rgsymRtf[isym].dflt;
        return ecApplyPropChange(rgsymRtf[isym].idx, param);
    case kwdChar:
        return ecParseChar(rgsymRtf[isym].idx);
    case kwdDest:
        return ecChangeDest(rgsymRtf[isym].idx);
    case kwdSpec:
        return ecParseSpecialKeyword(rgsymRtf[isym].idx);
    default:
        return ecBadTable;
    }
    return ecBadTable;
}

/* */
/* %%Function: ecChangeDest */
/* */
/* Change to the destination specified by idest. */
/* There's usually more to do here than this... */
/* */

int
ecChangeDest(IDEST idest)
{
    if (rds == rdsSkip)             /* if we're skipping text, */
        return ecOK;                /* don't do anything */

    switch (idest)
    {
    default:
        rds = rdsSkip;              /* when in doubt, skip it... */
        break;
    }
    return ecOK;
}

/* */
/* %%Function: ecEndGroupAction */
/* */
/* The destination specified by rds is coming to a close. */
/* If there's any cleanup that needs to be done, do it now. */
/* */

int
ecEndGroupAction(RDS rds)
{
    return ecOK;
}

/* */
/* %%Function: ecParseSpecialKeyword */
/* */
/* Evaluate an RTF control that needs special processing. */
/* */

int
ecParseSpecialKeyword(IPFN ipfn)
{
    if (rds == rdsSkip && ipfn != ipfnBin)  /* if we're skipping, and it's not */
        return ecOK;                        /* the \bin keyword, ignore it. */
    switch (ipfn)
    {
    case ipfnBin:
        ris = risBin;
        cbBin = lParam;
        break;
    case ipfnSkipDest:
        fSkipDestIfUnk = fTrue;
        break;
    case ipfnHex:
 ris = risHex;
 break;
    default:
        return ecBadTable;
    }
    return ecOK;
}
